/*--------------------------------------------------------------------------------
 * Adaptive Intelligence - Foundation Framework Class Library
 * Version 2.00
 * 
 * Hash Provider Class
 *      Provides a class for creating secure hash information on supplied data.
 *------------------------------------------------------------------------------*/

/*--------------------------------------------------------------------------------
 * System Imports
 *------------------------------------------------------------------------------*/
using System;
using System.Security.Cryptography;

namespace Adaptive.Foundation.Security
{
    /// <summary>
    /// Provides a class for creating secure hash information on supplied data.
    /// </summary>
    [Serializable()]
    public class HashProvider : DisposableObjectBase
    {
        /*--------------------------------------------------------------------------------
         * Private Member Declarations
         *------------------------------------------------------------------------------*/
        #region Private Member Declarations
        /// <summary>
        /// 32-byte hash value.
        /// </summary>
        private byte[] _firstHash;
        /// <summary>
        /// 64-byte hash value.
        /// </summary>
        private byte[] _secondHash;
        /// <summary>
        /// Hash check value.
        /// </summary>
        private byte[] _finalHash;
        #endregion

        /*--------------------------------------------------------------------------------
         * Constructor / Dispose / Destructor Methods
         *------------------------------------------------------------------------------*/
        #region Constructor / Dispose / Destructor Methods
        /// <summary>
        /// Initializes a new instance of the class.
        /// </summary>
        /// <remarks>
        /// This is the default constructor.
        /// </remarks>
        public HashProvider()
            : base()
        {
            _firstHash = new byte[32];
            _secondHash = new byte[64];
            _finalHash = new byte[16];
        }
        /// <summary>
        /// Deallocates internally allocated objects.
        /// </summary>
        /// <param name="disposing">
        /// A value indicating whether the object is being disposed.
        /// </param>
        protected override void Dispose(bool disposing)
        {
            if ((!Disposed) && (disposing))
            {
                Clear();
            }
            _firstHash = null;
            _secondHash = null;
            _finalHash = null;
            base.Dispose(disposing);
        }
        #endregion

        /*--------------------------------------------------------------------------------
         * Public Properties
         *------------------------------------------------------------------------------*/
        #region Public Properties
        /// <summary>
        /// Gets the 256-bit hash value for the last data hashed.
        /// </summary>
        /// <value>
        /// A byte array containing the value.
        /// </value>
        public byte[] FirstHashValue
        {
            get { return _firstHash; }
        }
        /// <summary>
        /// Gets the 512-bit hash value for the last data hashed.
        /// </summary>
        /// <value>
        /// A byte array containing the value.
        /// </value>
        public byte[] SecondHashValue
        {
            get { return _secondHash; }
        }
        /// <summary>
        /// Gets the 128-bit hash value used to validate the first and second hash values.
        /// </summary>
        /// <value>
        /// A byte array containing the value.
        /// </value>
        public byte[] FinalHashValue
        {
            get { return _finalHash; }
        }
        #endregion

        /*--------------------------------------------------------------------------------
         * Public Methods / Functions
         *------------------------------------------------------------------------------*/
        #region Public Methods / Functions
        /// <summary>
        /// Clears the contents of the object instance without disposing of the instance.
        /// </summary>
        public void Clear()
        {
            if (_firstHash != null)
                Array.Clear(_firstHash, 0, 32);
            if (_secondHash != null)
                Array.Clear(_secondHash, 0, 64);
            if (_finalHash != null)
                Array.Clear(_finalHash, 0, 16);
        }
        /// <summary>
        /// Computes the hash values for the supplied data.
        /// </summary>
        /// <param name="dataToHash">
        /// The data content to generate the hash codes for.
        /// </param>
        public virtual void ComputeHash(byte[] dataToHash)
        {
            SHA256Managed firstHashCreator = null;                  //Primary hash creator.
            SHA512Managed secondHashCreator = null;                 //Secondary hash creator.
            MD5CryptoServiceProvider finalHashCreator = null;       //Hash-of-hash values creator.
            byte[] combinedData = null;                             //Combination of values.

            //Create objects.
            firstHashCreator = new SHA256Managed();
            secondHashCreator = new SHA512Managed();
            finalHashCreator = new MD5CryptoServiceProvider();

            //Generate hash values.
            _firstHash = firstHashCreator.ComputeHash(dataToHash);
            _secondHash = secondHashCreator.ComputeHash(dataToHash);

            //Combine the items.
            combinedData = new byte[96];
            Array.Copy(_firstHash, 0, combinedData, 0, 32);
            Array.Copy(_secondHash, 0, combinedData, 32, 64);

            //Compute the hash check value.
            _finalHash = finalHashCreator.ComputeHash(combinedData);

            //Clear and return.
            Array.Clear(combinedData, 0, combinedData.Length);
            finalHashCreator = null;
            firstHashCreator = null;
            secondHashCreator = null;
            combinedData = null;
        }
        /// <summary>
        /// Compares the current data to determine if the supplied values match
        /// accordingly.
        /// </summary>
        /// <param name="data">
        /// The data content to be validated againts the current hash values.
        /// </param>
        public virtual bool ValidateContent(byte[] data)
        {
            ByteArrayComparer comparer = null;                      //Byte array comparer class.
            SHA256Managed firstHashCreator = null;                  //Primary hash creator.
            SHA512Managed secondHashCreator = null;                 //Secondary hash creator.
            MD5CryptoServiceProvider finalHashCreator = null;       //Hash-of-hash values creator.
            byte[] combinedData = null;                             //Combination of values.
            byte[] firstHash = null;                                //Temporary values.
            byte[] secondHash = null;                               //Temporary values.
            byte[] finalHash = null;                                //Temporary values.
            bool returnValue = false;                               //Return value.

            //Create objects.
            firstHashCreator = new SHA256Managed();
            secondHashCreator = new SHA512Managed();
            finalHashCreator = new MD5CryptoServiceProvider();

            //Generate hash values.
            firstHash = firstHashCreator.ComputeHash(data);
            secondHash = secondHashCreator.ComputeHash(data);

            //Combine the items.
            combinedData = new byte[96];
            Array.Copy(_firstHash, 0, combinedData, 0, 32);
            Array.Copy(_secondHash, 0, combinedData, 32, 64);

            //Compute the hash check value.
            finalHash = finalHashCreator.ComputeHash(combinedData);

            //Compare the values.
            comparer = new ByteArrayComparer();
            if (comparer.Compare(_finalHash, finalHash) == 0)
            {
                if (comparer.Compare(secondHash, _secondHash) == 0)
                {
                    if (comparer.Compare(_firstHash, firstHash) == 0)
                        returnValue = true;
                }
            }

            //Clear and return.
            Array.Clear(firstHash, 0, firstHash.Length);
            Array.Clear(secondHash, 0, secondHash.Length);
            Array.Clear(finalHash, 0, finalHash.Length);
            Array.Clear(combinedData, 0, combinedData.Length);
            firstHash = null;
            secondHash = null;
            finalHash = null;
            combinedData = null;
            comparer = null;

            return returnValue;
        }
        #endregion
    }
}
